home *** CD-ROM | disk | FTP | other *** search
- /*
- * Spawn a shell with file descriptors that look like this:
- *
- * +---------+
- * TTYin ---> | input | ---> screen (& virtual screen)
- * | program |
- * +---------+
- * | +---------+
- * pipe ----------> stdin | |
- * | shell |
- * TTYout <---------------------- stdout | |
- * +---------+
- *
- * The input program has a routine that duplicates the TTYin and sends it
- * down a pipe. The other end of the pipe is the stdin to the shell script.
- * This allows the characters to appear on the screen *and* be interpreted
- * by the shell script.
- */
-
- #include <stdio.h>
- #include <signal.h>
- #include <curses.h>
- #include <errno.h>
- #include "config.h"
- #include "dial_dir.h"
- #include "status.h"
-
- #ifdef BSD
- #ifndef SIGCLD
- #define SIGCLD SIGCHLD
- #endif /* SIGCLD */
- #include <sys/file.h>
- #else /* BSD */
- #include <fcntl.h>
- #endif /* BSD */
-
- void
- do_script(extra)
- char *extra;
- {
- extern int fd, errno;
- SIG_TYPE (*istat)(), (*qstat)(), (*cstat)();
- int epid, dup_pipe[2], want_out;
- char buf[80], *path, *findfile();
- void _exit(), error_win(), input_off(), do_input();
-
- /* if empty */
- if (*dir->script[dir->d_cur] == '\0')
- return;
- /* find the script file */
- if ((path = findfile(extra, dir->script[dir->d_cur])) == NULL) {
- /*
- * Fail quietly, if the script is actually a device.
- */
- if (chk_script(dir->script[dir->d_cur]))
- return;
-
- sprintf(buf, "Can't locate script \"%s\"", dir->script[dir->d_cur]);
- error_win(0, buf, "");
- return;
- }
- /* execute permission ? */
- if (access(path, 1)) {
- sprintf(buf, "\"%s\"", path);
- error_win(0, "No execute permission on script file", buf);
- return;
- }
- /* create a fd for duplicating input */
- if (pipe(dup_pipe) < 0)
- return;
-
- status->dup_fd = dup_pipe[1];
- /* start input duplication */
- do_input();
-
- if (!(epid = fork())) {
- /* create a new process group ID */
- #ifdef BSD
- setpgrp(0, getpid());
- #else /* BSD */
- setpgrp();
- #endif /* BSD */
- /* swap the stdin */
- close(0);
- dup(dup_pipe[0]);
- /* swap the stdout */
- close(1);
- dup(fd);
- #ifdef SETUGID
- setgid(getgid());
- setuid(getuid());
- #endif /* SETUGID */
-
- execl("/bin/sh", "sh", "-c", path, (char *) 0);
- _exit(1);
- }
- istat = signal(SIGINT, SIG_IGN);
- qstat = signal(SIGQUIT, SIG_IGN);
- cstat = signal(SIGCLD, SIG_IGN);
-
- /*
- * Check the keyboard while the script is being "played". If the
- * user hits the <ESC> key, then kill the entire process group
- * associated with the new shell.
- */
- want_out = 0;
- while(1) {
- switch(wait_key(stdscr, 1)) {
- case -1: /* timed out */
- break;
- case 27: /* a user abort */
- #ifdef BSD
- killpg(epid, SIGKILL);
- #else /* BSD */
- kill(-epid, SIGKILL);
- #endif /* BSD */
- want_out++;
- break;
- default:
- beep();
- break;
- }
- if (want_out)
- break;
- /* see if the process it still active */
- if ((kill(epid, 0) == -1) && errno == ESRCH)
- break;
- }
-
- signal(SIGINT, istat);
- signal(SIGQUIT, qstat);
- signal(SIGCLD, cstat);
- /* shut down the duplication of input */
- status->dup_fd = -1;
-
- #ifndef SHAREDMEM
- input_off();
- #endif /* SHAREDMEM */
-
- close(dup_pipe[0]);
- close(dup_pipe[1]);
- beep();
- return;
- }
-